/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/13 14:27
  *
  * @file       pd_timer_oc.c
  * @brief      TimerOC peripheral driver.
  *
  * @note       This file contains the peripheral driver for the TimerOC.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/13     Chris        the first version
  *
  ******************************************************************************
  */

#include <stm32f4xx_ll_tim.h>
#include "pd_timer_oc.h"

static void TimerOC_Init(TimerOC *this) {
    LL_TIM_OC_InitTypeDef TIM_OC_InitStruct;

    LL_TIM_OC_StructInit(&TIM_OC_InitStruct);

    TIM_OC_InitStruct.OCMode       = this->OCMode;
    TIM_OC_InitStruct.OCPolarity   = this->OCPolarity;
    TIM_OC_InitStruct.OCState      = this->OCState;
    TIM_OC_InitStruct.CompareValue = this->CompareValue;

    uint32_t *channel = this->timerChannel->channels;
    for (int i = 0; i < this->timerChannel->chSize; ++i) {
        LL_TIM_OC_Init(this->timer->TIMx, channel[i], &TIM_OC_InitStruct);
    }

    GPIO **gpio = this->timerChannel->gpios;
    for (int i = 0; i < this->timerChannel->gpioSize; ++i) {
        gpio[i]->init(gpio[i]);
    }
}

static void TimerOC_setCCR(TimerOC *this, uint32_t channel, uint32_t compareValue) {
    switch (channel) {
        case LL_TIM_CHANNEL_CH1:
            LL_TIM_OC_SetCompareCH1(this->timer->TIMx, compareValue);
            break;
        case LL_TIM_CHANNEL_CH2:
            LL_TIM_OC_SetCompareCH2(this->timer->TIMx, compareValue);
            break;
        case LL_TIM_CHANNEL_CH3:
            LL_TIM_OC_SetCompareCH3(this->timer->TIMx, compareValue);
            break;
        case LL_TIM_CHANNEL_CH4:
            LL_TIM_OC_SetCompareCH4(this->timer->TIMx, compareValue);
            break;
        default:
            break;
    }
}

static TimerOC *build(Timer *timer, TimerCh *timerChannel, uint32_t compareValue) {
    TimerOC *timerOC = malloc(sizeof(TimerOC));

    Driver_add(timerOC, GEN_PERM);

    timerOC->timer        = timer;
    timerOC->timerChannel = timerChannel;
    timerOC->OCMode       = LL_TIM_OCMODE_PWM1;
    timerOC->OCPolarity   = LL_TIM_OCPOLARITY_HIGH;
    timerOC->OCState      = LL_TIM_OCSTATE_ENABLE;
    timerOC->CompareValue = compareValue;

    timerOC->init         = &TimerOC_Init;
    timerOC->setCCR       = &TimerOC_setCCR;

    return timerOC;
}

const struct TimerOCClass TimerOCBuilder = {.build = &build};